using org.critterai.u3d;
using org.critterai.nav;
using org.critterai.nav.u3d;
using org.critterai.samples;
using UnityEngine;

public sealed class CorridorExplorerSim : MonoBehaviour
{
    public Transform startTransform;
    public Transform endTransform;
    public int maxPathSize = 1024;
    public int maxCorners = 4;

    private NavGroup mGroup;
    private BufferHandler<uint> mPath;
    private int mPathCount;
    private NavmeshPoint mPathStart;
    private NavmeshPoint mPathEnd;
    private PathCorridor mCorridor;
    private PathCorridorData mCorridorData;
    private BufferHandler<uint> mCornerPolys;

    private NavmeshQuery mNavmeshQuery;

    void Start()
    {
        InitializeNav();
    }

    void Update()
    {
        mPathStart = GetNavmeshPoint(startTransform.position);
        mPathEnd = GetNavmeshPoint(endTransform.position);

        if (mPathStart.polyRef != 0 && mPathEnd.polyRef != 0)
        {
            mCorridor.Reset(mPathStart);
            NavStatus status = mGroup.query.FindPath(mPathStart, mPathEnd, mGroup.filter, mPath.buffer, out mPathCount);

            mCorridor.Reset(mPathStart);
            if (NavUtil.Succeeded(status) && mPathCount > 0)
            {
                mCorridor.SetCorridor(mPathEnd.point, mPath.buffer, mPathCount);
            }
        }
    }

    private bool InitializeNav()
    {
        NavManagerProvider provider = (NavManagerProvider)FindObjectOfType(typeof(NavManagerProvider));

        if (provider == null)
        {
            Debug.LogError(string.Format("{0}: There is no {1} in the scene.", name, typeof(NavManagerProvider).Name));

            return false;
        }

        NavManager manager = provider.CreateManager();

        if (manager == null)
        {
            Debug.LogError(string.Format("{0}: Could not get the navigation manager.", name));

            return false;
        }      

        mGroup = manager.NavGroup;
        maxPathSize = Mathf.Max(1, maxPathSize);
        mPath = new BufferHandler<uint>("Max Path Size", 1, maxPathSize, 1, Mathf.Max(100, maxPathSize));
        mPathStart = new NavmeshPoint();
        mPathEnd = new NavmeshPoint();
        maxCorners = Mathf.Max(1, maxCorners);
        mCornerPolys = new BufferHandler<uint>("Max Corner Size", 1, maxCorners, 1, Mathf.Max(maxCorners, 20));
        mCorridor = new PathCorridor(mPath.MaxElementCount, mCornerPolys.MaxElementCount, mGroup.query, mGroup.filter);
        mCorridorData = new PathCorridorData(mPath.MaxElementCount);

        return true;
    }

    private NavmeshPoint GetNavmeshPoint(Vector3 searchPoint)
    {
        NavmeshPoint result;
        mGroup.query.GetNearestPoint(searchPoint, mGroup.extents, mGroup.filter, out result);

        return result;
    }

    void OnRenderObject()
    {
        if (mGroup.mesh != null)
        {
            mCorridor.GetData(mCorridorData);
            NavDebug.Draw(mGroup.mesh, false);
            NavDebug.Draw(mGroup.mesh, mCorridorData);
            NavDebug.Draw(mCorridor.Corners);

            Color c = NavDebug.positionColor;
            c.a = 0.25f;

            if (mPathStart.polyRef != 0)
            {
                DebugDraw.DiamondMarker(mPathStart.point, 1.0f, c);
            }

            c = NavDebug.goalColor;
            c.a = 0.25f;

            if (mPathEnd.polyRef != 0)
            {
                DebugDraw.DiamondMarker(mPathEnd.point, 1.0f, c);
            }
        }
    }
}
